package com.yanyeori.framework.datasource.mybatisplus.mapper;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.yanyeori.framework.datasource.mybatisplus.annotation.MultiTableId;
import org.apache.ibatis.annotations.Param;

import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * mybatis-plus增强mapper
 *
 * @author chenkuan 2021/4/23
 */
public interface BaseMapper<T> extends com.baomidou.mybatisplus.core.mapper.BaseMapper<T> {

    /**
     * 根据联合主键查询单个对象
     *
     * @param entity 实体对象
     * @return T 结果实体对象
     */
    default T selectByMultiId(T entity) {
        return selectOne(this.getQueryWrapper(entity));
    }

    /**
     * 根据联合主键修改数据
     *
     * @param entity 实体对象
     */
    default int updateByMultiId(T entity) {
        return update(entity, this.getQueryWrapper(entity));
    }

    /**
     * 根据联合主键修改数据
     * 全量更新，不忽略null字段
     *
     * @param entity 实体对象
     */
    int updateAllByMultiId(@Param(Constants.ENTITY) T entity);

    /**
     * 根据联合主键删除数据
     *
     * @param entity 实体对象
     */
    default int deleteByMultiId(T entity) {
        return delete(this.getQueryWrapper(entity));
    }

    /**
     * 根据 ID 更新固定的那几个字段
     * 全量更新，不忽略null字段
     *
     * @param entity 实体对象
     */
    int alwaysUpdateSomeColumnById(@Param(Constants.ENTITY) T entity);

    /**
     * 批量插入
     *
     * @param list 实体集合
     */
    int insertBatchSomeColumn(@Param("list") Collection<T> list);

    default QueryWrapper<T> getQueryWrapper(T t) {
        Set<Field> fields = this.getClassFields(t);
        if (fields.size() < 2) {
            throw new IllegalArgumentException(t.getClass().getSimpleName() + "要有两个或以上的主键");
        }
        try {
            T newInstance = (T) t.getClass().newInstance();
            for (Field field : fields) {
                if (!field.isAccessible()) {
                    field.setAccessible(true);
                }
                Object value = field.get(t);
                if (value == null) {
                    throw new IllegalArgumentException("主键字段" + field.getName() + "的值不能为null");
                }
                field.set(newInstance, value);
            }
            return new QueryWrapper<T>().setEntity(newInstance);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    Map<Class<?>, Set<Field>> CLASS_FIELD_MAP = new ConcurrentHashMap<>();

    default Set<Field> getClassFields(T t) {
        Class<?> clazz = t.getClass();
        if (!CLASS_FIELD_MAP.containsKey(clazz)) {
            for (Field field : clazz.getDeclaredFields()) {
                if (field.isAnnotationPresent(MultiTableId.class)) {
                    CLASS_FIELD_MAP.computeIfAbsent(clazz, k -> new CopyOnWriteArraySet<>()).add(field);
                }
            }
        }
        return CLASS_FIELD_MAP.get(clazz);
    }
}
